package org.chmodke.proxy.socks.util;

import java.io.IOException;
import java.io.InputStream;

/**
 * @author kehao
 */
public class P {
    public static final byte VER4 = 0x4;
    public static final byte VER5 = 0x5;
    public static final byte INVALID = 0x00;
    public static final byte FF = (byte) 0xff;
    public static final int FFFF = 0xFFFF;

    public static boolean isV4(byte data) {
        return VER4 == data;
    }

    public static boolean isV5(byte data) {
        return VER5 == data;
    }

    public static byte version(byte data) {
        return data;
    }

    public static class V4 {
        /**
         * request packet
         * |VN|CD|DSTPORT|DSTIP|USERID|NULL|
         * |--|--|-------|-----|------|----|
         * | 1| 1|      2|    4|      |   1|
         * <p>
         * response packet
         * |VN|CD|DSTPORT|DSTIP|
         * |--|--|-------|-----|
         * | 1| 1|      2|    4|
         */
        public static final byte CD_CONNECT = 0x01;
        public static final byte CD_BIND = 0x02;
        public static final byte RESP_ACCEPT_FORWARD = 0x5A;
        public static final byte RESP_REJECT_FORWARD = 0x5B;
        public static final byte RESP_REJECT_NOT_CONNECT = 0x5C;
        public static final byte RESP_REJECT_NOT_MATCH = 0x5D;
    }

    public static class V5 {
        public static final byte SUB_AUTH_VER = 0x01;

        //每个方法占1字节
        public static final byte AUTH_NONE = 0x00;
        public static final byte AUTH_GSSAPI = 0x01;
        public static final byte AUTH_PWD = 0x02;
        public static final byte AUTH_IANA_START = 0x03;
        public static final byte AUTH_IANA_END = 0x7F;
        public static final byte AUTH_PRIVATE_START = (byte) 0x80;
        public static final byte AUTH_PRIVATE_END = (byte) 0xFE;
        public static final byte AUTH_NOT_MATCH = (byte) 0xFF;
        public static final byte AUTH_SUCCEED = 0x00;
        public static final byte AUTH_FAIL = 0x01;


        public static final byte CD_CONNECT = 0x01;
        public static final byte CD_BIND = 0x02;
        public static final byte CD_UDP_ASSOCIATE = 0x03;


        public static final byte ADDRESS_TYPE_IPV4 = 0x01;
        public static final byte ADDRESS_TYPE_DOMAIN = 0x03;
        public static final byte ADDRESS_TYPE_IPV6 = 0x04;


        public static final byte RESP_SUCCEED = 0x00;
        public static final byte RESP_SERVER_FAULT = 0x01;
        public static final byte RESP_ALLOWED_CONNECT = 0x02;
        public static final byte RESP_CAN_NOT_CONNECT = 0x03;
        public static final byte RESP_INVALID_HOSTNAME = 0x04;
        public static final byte RESP_SERVER_REJECT = 0x05;
        public static final byte RESP_LLT = 0x06;
        public static final byte RESP_UNSUPPORTED_COMMAND = 0x07;
        public static final byte RESP_UNSUPPORTED_ADDRESS_TYPE = 0x08;
        public static final byte RESP_PRIVATE_START = 0x09;
        public static final byte RESP_PRIVATE_END = (byte) 0xFF;


        /**
         * VERSION	METHODS_COUNT	METHODS
         */
        public static boolean noneAuth(byte[] methods) {
            for (byte method : methods) {
                if (AUTH_NONE == method) {
                    return true;
                }
            }
            return false;
        }

        public static boolean isPwdAuth(byte[] methods) {
            for (byte method : methods) {
                if (AUTH_PWD == method) {
                    return true;
                }
            }
            return false;
        }


        /**
         * 获取目标的服务器地址
         *
         * @param type 地址类型
         * @param in   输入流
         * @return 地址
         * @throws IOException IOException
         */
        public static byte[] getHost(byte type, InputStream in) throws IOException {
            byte[] host = new byte[]{};
            switch (type) {
                case V5.ADDRESS_TYPE_IPV4:
                    host = new byte[4];
                    in.read(host);
                    return host;
                case V5.ADDRESS_TYPE_DOMAIN:
                    int l = in.read();
                    host = new byte[l];
                    in.read(host);
                    return host;
                case V5.ADDRESS_TYPE_IPV6:
                    host = new byte[16];
                    in.read(host);
                    return host;
                default:
                    break;
            }
            return host;
        }
    }
}
